package cn.zyx.sys.web;

import cn.zyx.common.GlobalAjaxJson;
import cn.zyx.common.GlobalErrorController;
import cn.zyx.common.properites.GlobalProperties;
import cn.zyx.common.utils.sys.JWTUtils;
import cn.zyx.common.utils.sys.UserUtils;
import cn.zyx.sys.entity.AccessKey;
import cn.zyx.sys.entity.User;
import cn.zyx.sys.service.AccessKeyService;
import cn.zyx.sys.service.UserService;
import com.auth0.jwt.JWT;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RestController
@Api(tags = "登录管理")
public class LoginController {

    @Autowired
    private UserService userService;

    @Autowired
    private AccessKeyService accessKeyService;

    /**
     * 从缓存中获取用户，没有从数据库查询
     * 验证密码是否正确（对密码进行hex解码）
     * 通过jwt生成token和refreshToken并返回
     * @return
     */
    @PostMapping("/sys/login")
    @ApiOperation("登录接口")
    public GlobalAjaxJson login(@RequestParam("userName") String userName,
                          @RequestParam("password") String password) {
        GlobalAjaxJson j = new GlobalAjaxJson();
        // 根据用户名查询用户，如果缓存中有就从缓存获取
        User user = UserUtils.getByLoginName(userName);
        // 验证用户密码是否正确
        if (user != null && UserService.validatePassword(password, user.getPassword())) {
            if (GlobalProperties.NO.equals(user.getLoginFlag())){
                j.setSuccess(false);
                j.setMsg("该用户已经被禁止登陆!");
            }else {
                j.setSuccess(true);
                // 通过jwt生成token
                j.put(JWTUtils.TOKEN, JWTUtils.createAccessToken(userName, user.getPassword()));
                j.put(JWTUtils.REFRESH_TOKEN, JWTUtils.createRefreshToken(userName, user.getPassword()));
            }
        } else {
            j.setSuccess(false);
            j.setMsg("用户名或者密码错误!");
        }
        return j;
    }

    /**
     * 通过accessKeyId 和 accessKeySecret获取token，供其他系统调用
     * @return
     */
    @PostMapping("/sys/accessKey")
    @ApiOperation("登录接口")
    public GlobalAjaxJson accessKey(@RequestParam("accessKeyId") String accessKeyId,
                                @RequestParam("accessKeySecret") String accessKeySecret) {
        GlobalAjaxJson j = new GlobalAjaxJson();
        // 根据accessKeyId查询，如果缓存中有就从缓存获取
        AccessKey accessKey = accessKeyService.getInfoByAccessKeyId(accessKeyId);
        // 验证用户密码是否正确
        if (accessKey != null && UserService.validatePassword(accessKeySecret, accessKey.getAccessKeySecret())) {
            if (GlobalProperties.NO.equals(accessKey.getIsActive())){
                j.setSuccess(false);
                j.setMsg("该accessKeyId已经被禁止登陆!");
            } else {
                j.setSuccess(true);
                // 通过jwt生成token
                j.put(JWTUtils.TOKEN, JWTUtils.createAccessToken(accessKeyId, accessKey.getAccessKeySecret()));
                j.put(JWTUtils.REFRESH_TOKEN, JWTUtils.createRefreshToken(accessKeyId, accessKey.getAccessKeySecret()));
            }
        } else {
            j.setSuccess(false);
            j.setMsg("accessKeyId或者accessKeySecret错误!");
        }
        return j;
    }

    /**
     * 验证refreshToken是否有效
     * 创建新的token
     * 判断refreshToken是否需要刷新 （token有效期是24小时，refreshToken有效期是3*24小时）
     * (refreshToken过期时间 - 当前时间点) 表示refreshToken还剩余的有效时长，如果小于2倍accessToken时长 ，则刷新 REFRESH_TOKEN
     * @return
     */
    @GetMapping("/sys/refreshToken")
    @ApiOperation("刷新token")
    public GlobalAjaxJson accessTokenRefresh(String refreshToken, HttpServletRequest request, HttpServletResponse response){

        if (JWTUtils.verify(refreshToken) == 1) {
            GlobalErrorController.response4022(request, response);

        }else if (JWTUtils.verify(refreshToken) == 2) {
            return GlobalAjaxJson.error("用户名密码错误");
        }

        String loginName = JWTUtils.getLoginName(refreshToken);
        String password = UserUtils.getByLoginName(loginName).getPassword();
        // 创建新的accessToken
        String accessToken = JWTUtils.createAccessToken(loginName, password);

        // 下面判断是否刷新 REFRESH_TOKEN，如果refreshToken 快过期了 需要重新生成一个替换掉
        long minTimeOfRefreshToken = 2 * GlobalProperties.newInstance().getEXPIRE_TIME();//REFRESH_TOKEN 有效时长是应该为accessToken有效时长的2倍
        Long refreshTokenExpirationTime = JWT.decode(refreshToken).getExpiresAt().getTime();//refreshToken创建的起始时间点
        // (refreshToken过期时间 - 当前时间点) 表示refreshToken还剩余的有效时长，如果小于2倍accessToken时长 ，则刷新 REFRESH_TOKEN
        if(refreshTokenExpirationTime - System.currentTimeMillis() <= minTimeOfRefreshToken){
            //刷新refreshToken
            refreshToken = JWTUtils.createRefreshToken(loginName, password);
        }

        return GlobalAjaxJson.success().put(JWTUtils.TOKEN, accessToken).put(JWTUtils.REFRESH_TOKEN, refreshToken);
    }

    /**
     * 退出登录
     * @throws IOException
     */
    @ApiOperation("用户退出")
    @GetMapping("/sys/logout")
    public GlobalAjaxJson logout() {
        GlobalAjaxJson j = new GlobalAjaxJson();
        String token = UserUtils.getToken();
        if (StringUtils.isNotBlank(token)) {
            UserUtils.clearCache();
            UserUtils.getSubject().logout();
        }
        j.setMsg("退出成功");
        return j;
    }

    @PostMapping("/401")
    @ApiOperation("401")
    public GlobalAjaxJson login() {
        GlobalAjaxJson j = new GlobalAjaxJson();
        return j;
    }
}
